%{
#include <fstream>
#include "SysY_tree.h"
#include "type.h"
Program ast_root;

void yyerror(char *s, ...);
int yylex();
int error_num = 0;
extern int line_number;
extern std::ofstream fout;
extern IdTable id_table;
%}
%union{
    char* error_msg;
    Symbol symbol_token;
    double float_token; // 对于SysY的浮点常量，我们需要先以double类型计算，再在语法树节点创建的时候转为float
    int int_token;
    Program program;  
    CompUnit comp_unit;  std::vector<CompUnit>* comps; 
    Decl decl;
    Def def;  std::vector<Def>* defs;
    FuncDef func_def;
    Expression expression;  std::vector<Expression>* expressions;
    Stmt stmt;
    Block block;
    InitVal initval;  std::vector<InitVal>* initvals;
    FuncFParam formal;   std::vector<FuncFParam>* formals;
    BlockItem block_item;   std::vector<BlockItem>* block_items;
}
//declare the terminals 终结符，估计是词法分析来的
%token <symbol_token> STR_CONST IDENT
%token <float_token> FLOAT_CONST
%token <int_token> INT_CONST
%token LEQ GEQ EQ NE // <=   >=   ==   != 
%token AND OR // &&    ||
%token CONST IF ELSE WHILE NONE_TYPE INT FLOAT FOR DOUBLE BOOL VOID// DOUBLE及以后是我额外加的，应该没问题吧但是这里好像不让改来着
%token RETURN BREAK CONTINUE ERROR TODO

//give the type of nonterminals  非终结符的类型
%type <program> Program
%type <comp_unit> CompUnit 
%type <comps> Comp_list
%type <decl> Decl VarDecl ConstDecl
%type <def> ConstDef VarDef
%type <defs> ConstDef_list VarDef_list 
%type <func_def> FuncDef 
%type <expression> Exp LOrExp AddExp MulExp RelExp EqExp LAndExp UnaryExp PrimaryExp
%type <expression> ConstExp Lval FuncRParams Cond 
%type <expression> IntConst FloatConst
%type <expressions> array_tail Exp_list const_array_tail; 
%type <stmt> Stmt 
%type <block> Block
%type <block_item> BlockItem
%type <block_items> BlockItem_list
%type <initval> ConstInitVal VarInitVal  
%type <initvals> VarInitVal_list ConstInitVal_list
%type <formal> FuncFParam 
%type <formals> FuncFParams

// THEN和ELSE用于处理if和else的移进-规约冲突
%precedence THEN
%precedence ELSE
%%
//一个程序由一系列编译单元（Comp_list）组成
Program 
:Comp_list
{
    @$ = @1;
    ast_root = new __Program($1);
    ast_root->SetLineNumber(line_number);
};

//编译单元列表，它可以是一个单独的编译单元，也可以是编译单元列表后跟一个编译单元
Comp_list
:CompUnit 
{
    $$ = new std::vector<CompUnit>;
    ($$)->push_back($1);
}
|Comp_list CompUnit
{
    ($1)->push_back($2);
    $$ = $1;
};

//单个编译单元，它可以是一个声明或一个函数定义
CompUnit
:Decl{
    $$ = new CompUnit_Decl($1); 
    $$->SetLineNumber(line_number);
}
|FuncDef{
    $$ = new CompUnit_FuncDef($1); 
    $$->SetLineNumber(line_number);
}
;

//定义声明，它可以是一个变量声明或一个常量声明
Decl
:VarDecl{
    $$ = $1; 
    $$->SetLineNumber(line_number);
}
|ConstDecl{
    $$ = $1; 
    $$->SetLineNumber(line_number);
}
;

//变量声明，它由类型说明符、变量定义列表和分号组成int a=5,b=2;
VarDecl
:INT VarDef_list ';'{
    $$ = new VarDecl(Type::INT,$2); 
    $$->SetLineNumber(line_number);
}
|FLOAT VarDef_list ';'{
    $$ = new VarDecl(Type::FLOAT, $2); 
    $$->SetLineNumber(line_number);
}
|DOUBLE VarDef_list ';'{
    $$ = new VarDecl(Type::DOUBLE, $2); 
    $$->SetLineNumber(line_number);
}
|BOOL VarDef_list ';'{
    $$ = new VarDecl(Type::BOOL, $2); 
    $$->SetLineNumber(line_number);
}
;

// TODO(): 考虑变量定义更多情况  
//常量声明
ConstDecl
:CONST INT ConstDef_list ';'{
    $$ = new ConstDecl(Type::INT,$3); 
    $$->SetLineNumber(line_number);
}
|CONST FLOAT ConstDef_list ';'{
    $$ = new ConstDecl(Type::FLOAT,$3); 
    $$->SetLineNumber(line_number);
}
|CONST DOUBLE ConstDef_list ';'{
    $$ = new ConstDecl(Type::DOUBLE,$3); 
    $$->SetLineNumber(line_number);
}
|CONST BOOL ConstDef_list ';'{
    $$ = new ConstDecl(Type::BOOL,$3); 
    $$->SetLineNumber(line_number);
}
;

// TODO(): 考虑变量定义更多情况  

// 定义变量定义列表   x=1|x=1,y=2,z...
VarDef_list
:VarDef
{
    $$ = new std::vector<Def>;
    ($$)->push_back($1);
}
| VarDef_list ',' VarDef
{
    ($1)->push_back($3);
    $$ = $1;
}
;

// 定义常量定义列表
ConstDef_list
: ConstDef
{
    $$ = new std::vector<Def>;
    ($$)->push_back($1);
}
| ConstDef_list ',' ConstDef
{
    ($1)->push_back($3);
    $$ = $1;
}
;

//函数定义
FuncDef
:INT IDENT '(' FuncFParams ')' Block  //带参数
{
    $$ = new __FuncDef(Type::INT,$2,$4,$6);
    $$->SetLineNumber(line_number);
}
|INT IDENT '(' ')' Block//不带参数
{
    $$ = new __FuncDef(Type::INT,$2,new std::vector<FuncFParam>(),$5);
    $$->SetLineNumber(line_number);
}
|FLOAT IDENT '('FuncFParams ')' Block
{
    $$ = new __FuncDef(Type::FLOAT,$2,$4,$6); 
    $$->SetLineNumber(line_number);
}
|FLOAT IDENT '(' ')' Block
{
    $$ = new __FuncDef(Type::FLOAT,$2,new std::vector<FuncFParam>(),$5); 
    $$->SetLineNumber(line_number);
}
|BOOL IDENT '(' FuncFParams')' Block
{
    $$ = new __FuncDef(Type::BOOL ,$2,$4,$6); 
    $$->SetLineNumber(line_number);
}
|BOOL  IDENT '(' ')' Block
{
    $$ = new __FuncDef(Type::BOOL ,$2,new std::vector<FuncFParam>(),$5); 
    $$->SetLineNumber(line_number);
}
|VOID  IDENT '(' FuncFParams')' Block
{
    $$ = new __FuncDef(Type::VOID ,$2,$4,$6); 
    $$->SetLineNumber(line_number);
}
|VOID IDENT '(' ')' Block
{
    $$ = new __FuncDef(Type::VOID ,$2,new std::vector<FuncFParam>(),$5); 
    $$->SetLineNumber(line_number);
}
;
// TODO(): 考虑函数定义更多情况    

//变量定义，变量名，[可选的下标]，可选的初始化值a=5  b  a[]=
VarDef
:IDENT '=' VarInitVal
{$$ = new VarDef($1,nullptr,$3); $$->SetLineNumber(line_number);}
|IDENT
{$$ = new VarDef_no_init($1,nullptr); $$->SetLineNumber(line_number);}
|IDENT array_tail '='  VarInitVal
{
    $$ = new VarDef($1, $2, $4);
    $$->SetLineNumber(line_number);
}
|IDENT array_tail
{
    $$ = new VarDef_no_init($1, $2);
    $$->SetLineNumber(line_number);
}
;   
// TODO(): 考虑变量定义更多情况  

//常量定义需要赋初值，定义常量、数组 ?:第二个参数传什么
ConstDef
//:TODO{}
:IDENT '=' ConstInitVal
{$$ = new ConstDef($1,nullptr,$3); $$->SetLineNumber(line_number);}
|IDENT const_array_tail '='  ConstInitVal 
{
    $$ = new ConstDef($1, $2, $4); 
    $$->SetLineNumber(line_number);
}
;   

//常量初始化值，可以是单个常量表达式（ConstExp）、一个由花括号包围的常量初始化值列表（ConstInitVal_list）、{}一个空的初始化值列
ConstInitVal
//:TODO{}
: ConstExp
{
    $$ = new ConstInitVal_exp($1);
    $$->SetLineNumber(line_number);
}
|'{' ConstInitVal_list '}'{
    $$ = new ConstInitVal($2);
    $$->SetLineNumber(line_number);
}
|'{' '}' 
{   
    std::vector<InitVal> *initval=new std::vector<InitVal>();
    $$ = new ConstInitVal(initval);
    $$->SetLineNumber(line_number);
}
;

//变量初始化值，
VarInitVal
//:TODO{}
:Exp
{
    $$ = new VarInitVal_exp($1);
    $$->SetLineNumber(line_number);
}
|'{'VarInitVal_list'}'{
    $$ = new VarInitVal($2);
    $$->SetLineNumber(line_number);
}
|'{' '}'{
    std::vector<InitVal> *initval=new std::vector<InitVal>();
    $$ = new VarInitVal(initval);
    $$->SetLineNumber(line_number);
}
;

VarInitVal_list
//:TODO{}
:VarInitVal{
    $$ = new std::vector<InitVal>;
    ($$)->push_back($1);
}
|VarInitVal_list',' VarInitVal
{
    ($1)->push_back($3);
    $$ = $1;
}
;
//常量初始化值列表
ConstInitVal_list
//:TODO{}
:ConstInitVal{
    $$ = new std::vector<InitVal>;
    ($$)->push_back($1);
}
| ConstInitVal_list ',' ConstInitVal
{
    ($1)->push_back($3);
    $$ = $1;
}
;

FuncFParams
:FuncFParam{
    $$ = new std::vector<FuncFParam>;
    ($$)->push_back($1);
}
|FuncFParams ',' FuncFParam{
    ($1)->push_back($3);
    $$ = $1;
}
;

FuncFParam
:INT IDENT{
    $$ = new __FuncFParam(Type::INT,$2,nullptr);
    $$->SetLineNumber(line_number);
}
| FLOAT IDENT
{
    $$ = new __FuncFParam(Type::FLOAT, $2, nullptr);
    $$->SetLineNumber(line_number);
}
| DOUBLE IDENT
{
    $$ = new __FuncFParam(Type::DOUBLE, $2, nullptr);
    $$->SetLineNumber(line_number);
}
| BOOL IDENT
{
    $$ = new __FuncFParam(Type::BOOL, $2, nullptr);
    $$->SetLineNumber(line_number);
}
//带维度
| INT IDENT '[' ']' array_tail
{   
    //第一维是空
    $5->insert($5->begin(),nullptr);
    $$ = new __FuncFParam(Type::INT, $2, $5); 
    $$->SetLineNumber(line_number);
}
| FLOAT IDENT '[' ']'array_tail
{
    $5->insert($5->begin(),nullptr);
    $$ = new __FuncFParam(Type::FLOAT, $2, $5);
    $$->SetLineNumber(line_number);
}
| DOUBLE IDENT '[' ']'array_tail
{
    $5->insert($5->begin(),nullptr);
    $$ = new __FuncFParam(Type::DOUBLE, $2, $5);
    $$->SetLineNumber(line_number);
}
| BOOL IDENT '[' ']' array_tail
{   
    $5->insert($5->begin(),nullptr);
    $$ = new __FuncFParam(Type::BOOL, $2, $5);
    $$->SetLineNumber(line_number);
}
//匹配没有指定维度的数组 int arr[]
| INT IDENT '[' ']'
{   
    std::vector<Expression>* tmp = new std::vector<Expression>;
    tmp->push_back(nullptr);
    $$ = new __FuncFParam(Type::INT, $2, tmp); 
    $$->SetLineNumber(line_number);
}
| FLOAT IDENT '[' ']'
{   
    std::vector<Expression>* tmp = new std::vector<Expression>;
    tmp->push_back(nullptr);
    $$ = new __FuncFParam(Type::FLOAT, $2, tmp);
    $$->SetLineNumber(line_number);
}
| DOUBLE IDENT '[' ']'
{   
    std::vector<Expression>* tmp = new std::vector<Expression>;
    tmp->push_back(nullptr);
    $$ = new __FuncFParam(Type::DOUBLE, $2, tmp);
    $$->SetLineNumber(line_number);
}
| BOOL IDENT '[' ']'
{   
    std::vector<Expression>* tmp = new std::vector<Expression>;
    tmp->push_back(nullptr);
    $$ = new __FuncFParam(Type::BOOL, $2, tmp);
    $$->SetLineNumber(line_number);
};
// TODO(): 考虑函数形参更多情况

Block
:'{' BlockItem_list '}'{
    $$ = new __Block($2);
    $$->SetLineNumber(line_number);
}
|'{' '}'{
    $$ = new __Block(new std::vector<BlockItem>);
    $$->SetLineNumber(line_number);
}
;

//语句列表
BlockItem_list
//:TODO{}
:BlockItem{
    $$ = new std::vector<BlockItem>;
    ($$)->push_back($1);
}
|BlockItem_list BlockItem{
    ($1)->push_back($2);
    $$ = $1;
}
;

//语句，包括声明和语句
BlockItem
//:TODO{}
: Decl
{
    $$ = new BlockItem_Decl($1);
    $$->SetLineNumber(line_number);
}
| Stmt
{
    $$ = new BlockItem_Stmt($1);
    $$->SetLineNumber(line_number);
}
;

//语句，空语句（只有一个;）、赋值语句、表达式语句、代码块、if、ifelse、while、continue、break、return
Stmt
//:TODO{}
:';'{
    $$ = new null_stmt();
    $$->SetLineNumber(line_number);
}
|
Lval'='Exp';'{
 $$ = new assign_stmt($1,$3);
    $$->SetLineNumber(line_number);   
}
|Exp ';'{
    $$ = new expr_stmt($1);
    $$->SetLineNumber(line_number); 
}
|Block{
    $$ = new block_stmt($1);
    $$->SetLineNumber(line_number);
}
|IF '(' Cond ')' Stmt %prec THEN{
    $$ = new if_stmt($3,$5);
    $$->SetLineNumber(line_number);
}
|IF '(' Cond ')' Stmt ELSE Stmt{
    $$ = new ifelse_stmt($3,$5,$7);
    $$->SetLineNumber(line_number);
}
|WHILE '(' Cond ')' Stmt{
    $$ = new while_stmt($3, $5);
    $$->SetLineNumber(line_number);
}
|CONTINUE ';'{
    $$ = new continue_stmt();
    $$->SetLineNumber(line_number);
}
|BREAK ';'{
    $$ = new break_stmt();
    $$->SetLineNumber(line_number);
}
|RETURN Exp';'{
    $$ = new return_stmt($2);
    $$->SetLineNumber(line_number);
}
|RETURN ';'{
    $$ = new return_stmt_void();
    $$->SetLineNumber(line_number);
}
;
Exp
:AddExp{$$ = $1; $$->SetLineNumber(line_number);}
;

Cond
:LOrExp{$$ = $1; $$->SetLineNumber(line_number);}
;

//作为左值的变量，name{[dim]}   eg. a[4][5+4][3+4*9]
Lval
//:TODO{}
:IDENT{
    $$ = new Lval($1,nullptr); 
    $$->SetLineNumber(line_number);
}
|IDENT array_tail{
    $$ = new Lval($1,$2); 
    $$->SetLineNumber(line_number);
}
;



//主表达式，表达式中不能被进一步分解的最基本部分，字面量、变量引用、以及被括号包围的表达式等
PrimaryExp
//:TODO{}
:'('Exp')'{
    $$ = new PrimaryExp_branch($2);
    $$->SetLineNumber(line_number);
}
|Lval{
    $$=$1;
    $$->SetLineNumber(line_number);
}
|IntConst{
    $$=$1;
    $$->SetLineNumber(line_number);
}
|FloatConst{
    $$=$1;
    $$->SetLineNumber(line_number);
}
;

IntConst
:INT_CONST{
    $$ = new IntConst($1);
    $$->SetLineNumber(line_number);
}
;

FloatConst
:FLOAT_CONST{
    $$ = new FloatConst($1);
    $$->SetLineNumber(line_number);
}
;

//一元表达式。一元表达式包括单个操作符前面或后面的表达式，例如 函数调用、++x、x++、-x、!x 等。
UnaryExp
:PrimaryExp{$$ = $1;}
|IDENT '(' FuncRParams ')'{
    $$ = new Func_call($1,$3);
    $$->SetLineNumber(line_number);
}
|IDENT '(' ')'{
    // 在sylib.h这个文件中,starttime()是一个宏定义
    // #define starttime() _sysy_starttime(__LINE__)
    // 我们在语法分析中将其替换为_sysy_starttime(line_number)
    // stoptime同理
    if($1->get_string() == "starttime"){
        auto params = new std::vector<Expression>;
        params->push_back(new IntConst(line_number));
        Expression temp = new FuncRParams(params);
        $$ = new Func_call(id_table.add_id("_sysy_starttime"),temp);
        $$->SetLineNumber(line_number);
    }
    else if($1->get_string() == "stoptime"){
        auto params = new std::vector<Expression>;
        params->push_back(new IntConst(line_number));
        Expression temp = new FuncRParams(params);
        $$ = new Func_call(id_table.add_id("_sysy_stoptime"),temp);
        $$->SetLineNumber(line_number);
    }
    else{
        $$ = new Func_call($1,nullptr);
        $$->SetLineNumber(line_number);
    }
}
|'+' UnaryExp{
    $$ = new UnaryExp_plus($2);
    $$->SetLineNumber(line_number);
}
|'-' UnaryExp{
    $$ = new UnaryExp_neg($2);
    $$->SetLineNumber(line_number);
}
|'!' UnaryExp{
    $$ = new UnaryExp_not($2);
    $$->SetLineNumber(line_number);
}
;

//函数调用的参数列表。指针指向一个表达式列表，列表中的每个表达式代表函数调用中的一个参数
FuncRParams
:Exp_list{
    $$ = new FuncRParams($1);
    $$->SetLineNumber(line_number);
}
;


Exp_list
//:TODO{}
:Exp{
    $$ = new std::vector<Expression>;
    $$->push_back($1);
}
|Exp_list','Exp{
    $1->push_back($3);
    $$=$1;
}
;

MulExp
//:TODO{}
:UnaryExp{
    $$ = $1;
    $$->SetLineNumber(line_number);
}
|
MulExp '*' UnaryExp{
    $$ = new MulExp_mul($1,$3); 
    $$->SetLineNumber(line_number);
}
|
MulExp '/' UnaryExp{
    $$ = new MulExp_div($1,$3); 
    $$->SetLineNumber(line_number);
}
|
MulExp '%' UnaryExp{
    $$ = new MulExp_mod($1,$3); 
    $$->SetLineNumber(line_number);
}
;

AddExp
:MulExp{
    $$ = $1;
    $$->SetLineNumber(line_number);
}
|AddExp '+' MulExp{
    $$ = new AddExp_plus($1,$3); 
    $$->SetLineNumber(line_number);
}
|AddExp '-' MulExp{
    $$ = new AddExp_sub($1,$3); 
    $$->SetLineNumber(line_number);
}
;

RelExp
//:TODO{}
:AddExp{
    $$ = $1;
    $$->SetLineNumber(line_number);
}
|
RelExp LEQ AddExp{
    $$ = new RelExp_leq($1,$3); 
    $$->SetLineNumber(line_number);
}
|
RelExp '<' AddExp{
    $$ = new RelExp_lt($1,$3); 
    $$->SetLineNumber(line_number);
}
|
RelExp GEQ AddExp{
    $$ = new RelExp_geq($1,$3); 
    $$->SetLineNumber(line_number);
}
|
RelExp '>' AddExp{
    $$ = new RelExp_gt($1,$3); 
    $$->SetLineNumber(line_number);
}
;

EqExp
//:TODO{}
:RelExp{$$ = $1;$$->SetLineNumber(line_number);}
|EqExp EQ RelExp{
    $$ = new EqExp_eq($1,$3); 
    $$->SetLineNumber(line_number);
}
|
EqExp NE RelExp{
    $$ = new EqExp_neq($1,$3); 
    $$->SetLineNumber(line_number);
}
;

LAndExp
:EqExp{
    $$ = $1;
    $$->SetLineNumber(line_number);
}
|LAndExp AND EqExp{
    $$ = new LAndExp_and($1,$3); 
    $$->SetLineNumber(line_number);
}
;

LOrExp
:LAndExp{
    $$ = $1;
    $$->SetLineNumber(line_number);
}
|LOrExp OR LAndExp{
    $$ = new LOrExp_or($1,$3); 
    $$->SetLineNumber(line_number);
}
;


ConstExp
//:TODO{}
:AddExp{
    $$ = new ConstExp($1); 
    $$->SetLineNumber(line_number);
}
;

// TODO: 也许你需要添加更多的非终结符

array_tail
: array_tail'[' Exp ']' 
{   
    ($1)->push_back($3);
    $$ = $1;
}
| '[' Exp ']'
{
    $$ = new std::vector<Expression>;
    $$ -> push_back($2);
}
|
'['  ']'{
     $$ = nullptr;
}
|
array_tail '['  ']'{
     //($1)->push_back(nullptr);
    $$ = $1;
}
;
const_array_tail
:const_array_tail'[' Exp ']' 
{   
    ($1)->push_back($3);
    $$ = $1;
}
| '[' Exp ']'
{
    $$ = new std::vector<Expression>;
    $$ -> push_back($2);
};

%% 

void yyerror(char* s, ...)
{
    ++error_num;
    fout<<"parser error in line "<<line_number<<"\n";
}